﻿using Cxuu.Common;
using Cxuu.Models;
using Cxuu.Service;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Net.Http.Headers;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace Cxuu.Web.Admin
{
    [Area("Admin")]
    [Authorize]
    public class UploadController : Base
    {
        private readonly ConfigService configService;
        private readonly AttmentService _attment;

        private readonly string _targetFilePath = "C:\\files\\TempDir";

        public UploadController(ConfigService config, AttmentService attmentService)
        {
            configService = config;
            _attment = attmentService;
        }

        [HttpPost]
        public async Task<IActionResult> Upload(IFormFile file, int uid, string source, string type = "")
        {
            ViewUploadInfo uploadInfo = new()
            {
                Success = false
            };

            long size = file.Length;       //统计文件大小

            if (size < 0 || size == 0)        //文件大小 0 才上传
            {
                uploadInfo.Error = "上传文件不存在！";
                return Json(uploadInfo);
            }

            string fileName = file.FileName;

            EditConfigSiteInfo configSiteInfo = await configService.GetByNameAsync();
            string baseDir = configSiteInfo.BaseDir;

            //图片限制信息
            string[] imgageExts = configSiteInfo.ImageExt.Split(',');
            int imageSize = configSiteInfo.ImageSize * 1024;

            //文件限制信息
            string[] fileExts = configSiteInfo.FileExt.Split(',');
            int fileSize = configSiteInfo.FileSize * 1024;

            string fileExt = Path.GetExtension(fileName);//文件后缀
            string uploadDir;

            if (((IList)imgageExts).Contains(fileExt))
            {
                if (!imgageExts.Any(m => m.Equals(fileExt, StringComparison.OrdinalIgnoreCase)))
                {
                    uploadInfo.Error = "上传图片类型不合法！";
                    return Json(uploadInfo);
                }
                if (size > imageSize)
                {
                    uploadInfo.Error = "上传文件超过系统大小限制！";
                    return Json(uploadInfo);
                }
                uploadDir = configSiteInfo.ImageDir;
            }
            else if (((IList)fileExts).Contains(fileExt))
            {
                if (!fileExts.Any(m => m.Equals(fileExt, StringComparison.OrdinalIgnoreCase)))
                {
                    uploadInfo.Error = "上传文件类型不合法！";
                    return Json(uploadInfo);
                }
                if (size > fileSize)
                {
                    uploadInfo.Error = "上传文件超过系统大小限制！";
                    return Json(uploadInfo);
                }
                uploadDir = configSiteInfo.FileDir;
            }
            else
            {
                uploadInfo.Error = "非法上传！";
                return Json(uploadInfo);
            }

            string dateDir = DateTime.Now.ToString("yyyyMM");
            var dirPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", baseDir, uploadDir, dateDir);

            if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);//如目录不存在，则以当前日期创新目录

            string newFileName = MD5Utility.MD5Encrypt16(fileName + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff:ffffff")).ToLower(); //获取当前时间微秒 生成MD5
            string saveFilePath = Path.Combine(dirPath, newFileName + fileExt); //当前上传文件应存放的位置 path.combine 内置跨平台文件系统路径拼接方法
            using var stream = System.IO.File.Create(saveFilePath);
            try
            {
                await file.CopyToAsync(stream);     //上传文件
                uploadInfo.Success = true;
                uploadInfo.Filename = fileName;
                uploadInfo.Ext = fileExt;
                uploadInfo.Url = "/" + baseDir + "/" + uploadDir + "/" + dateDir + "/" + newFileName + fileExt;

                Attment attment = new()
                {
                    Filename = fileName,
                    Ext = fileExt,
                    Url = uploadInfo.Url,
                    Size = size / 1024,
                    Source = source,
                    Uid = uid,
                    Time = DateTime.Now
                };
                object attId = await _attment.InsertAsync(attment);

                return type switch
                {
                    "Tinymce" => Json(new { location = uploadInfo.Url, status = 200 }),
                    "layui" => Json(new { data = uploadInfo, status = 1, pkey = attId, info = "上传成功" }),
                    "layuiImg" => Json(new { data = uploadInfo, status = 1, info = "上传成功" }),
                    _ => Json(uploadInfo),
                };
            }
            catch (Exception ex)        //上传异常处理
            {
                uploadInfo.Success = false;
                uploadInfo.Error = ex.ToString();
                return Json(uploadInfo);
            }
        }

        [HttpPost]
        public async Task<IActionResult> MutiUplaod(List<IFormFile> file, int uid)
        {
            ViewUploadInfo uploadInfo = new();

            foreach (var formFile in file)
            {
                if (formFile.Length > 0)
                {
                    FileInfo fi = new(formFile.FileName);
                    string ext = fi.Extension;
                    var orgFileName = fi.Name;
                    //var newFileName = Guid.NewGuid() + ext;
                    var newFileName = DateTime.Now.ToString("yyyyMMddhhmmss") + formFile.FileName;

                    var uploads = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "uploads", "new");
                    var filePath = Path.Combine(uploads, newFileName);
                    using (var stream = new FileStream(filePath, FileMode.Create))
                    {
                        await formFile.CopyToAsync(stream);
                    }
                    uploadInfo.Success = true;
                }
                else
                {

                    uploadInfo.Error = "上传文件出错!";
                }
            }
            return Json(uploadInfo);
        }

        /// <summary>
        /// 流式文件上传
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> UploadingStream()
        {

            //获取boundary
            var boundary = HeaderUtilities.RemoveQuotes(MediaTypeHeaderValue.Parse(Request.ContentType).Boundary).Value;
            //得到reader
            var reader = new MultipartReader(boundary, HttpContext.Request.Body);
            //{ BodyLengthLimit = 2000 };//
            var section = await reader.ReadNextSectionAsync();

            //读取section
            while (section != null)
            {
                var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
                if (hasContentDispositionHeader)
                {
                    var trustedFileNameForFileStorage = Path.GetRandomFileName();
                    await WriteFileAsync(section.Body, Path.Combine(_targetFilePath, trustedFileNameForFileStorage));
                }
                section = await reader.ReadNextSectionAsync();
            }
            return Created(nameof(UploadController), null);
        }


        /// <summary>
        /// 写文件导到磁盘
        /// </summary>
        /// <param name="stream">流</param>
        /// <param name="path">文件保存路径</param>
        /// <returns></returns>
        public static async Task<int> WriteFileAsync(Stream stream, string path)
        {
            const int FILE_WRITE_SIZE = 84975;//写出缓冲区大小
            int writeCount = 0;
            using (FileStream fileStream = new(path, FileMode.Create, FileAccess.Write, FileShare.Write, FILE_WRITE_SIZE, true))
            {
                byte[] byteArr = new byte[FILE_WRITE_SIZE];
                int readCount = 0;
                while ((readCount = await stream.ReadAsync(byteArr, 0, byteArr.Length)) > 0)
                {
                    await fileStream.WriteAsync(byteArr, 0, readCount);
                    writeCount += readCount;
                }
            }
            return writeCount;
        }
    }
}
